import type { SweetAlertOptions, SweetAlertResult } from 'sweetalert2'
import Swal from 'sweetalert2'
import { MergeHandler } from './merge_handler'
import { ToolKit } from './utils/toolkit'

/**
 * SweetAlert2 Toast 管理器 (https://sweetalert2.github.io/)
 */
export class ToastManager {
  private static instance: ToastManager
  private readonly mergeHandler: MergeHandler = MergeHandler.getInstance()

  private readonly BASE_CONFIG: SweetAlertOptions = {
    toast: false,
    position: 'center',
    animation: true,
    timerProgressBar: true,
    didOpen: (toast: HTMLElement) => {
      toast.addEventListener('mouseenter', Swal.stopTimer)
      toast.addEventListener('mouseleave', Swal.resumeTimer)
    },
    customClass: {
      container: 'swal2-z-index-top',
    },
    buttonsStyling: false,
  }

  private readonly PRESETS: Record<string, SweetAlertOptions> = {
    confirm: {
      showConfirmButton: true,
      showCancelButton: true,
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      customClass: {
        confirmButton: 'btn btn-primary',
        cancelButton: 'btn btn-outline-secondary',
      },
    },
    reset: {
      showConfirmButton: true,
      showCancelButton: true,
      confirmButtonText: '确认重置',
      cancelButtonText: '取消操作',
      reverseButtons: false,
      customClass: {
        confirmButton: 'btn btn-primary',
        cancelButton: 'btn btn-outline-secondary',
      },
    },
    alert: {
      timer: 3000,
      showConfirmButton: true,
      confirmButtonText: 'OK',
      customClass: {
        confirmButton: 'btn btn-info',
      },
    },
    toast: {
      showConfirmButton: false,
      timer: 3000,
    },
  }

  public static getInstance(): ToastManager {
    if (!ToastManager.instance) {
      ToastManager.instance = new ToastManager()
    }
    return ToastManager.instance
  }

  /**
   * 显示确认对话框
   * @param options SweetAlert2 配置选项
   * @returns 包含用户选择的结果
   */
  public confirm(options: SweetAlertOptions = {}): Promise<SweetAlertResult> {
    return this.show('confirm', options)
  }

  /**
   * 显示重置对话框
   * @param options SweetAlert2 配置选项
   * @returns 包含用户选择的结果
   */
  public reset(options: SweetAlertOptions = {}): Promise<SweetAlertResult> {
    return this.show('reset', options)
  }

  /**
   * 显示警告提示
   * @param options SweetAlert2 配置选项
   * @returns 包含用户选择的结果
   */
  public alert(options: SweetAlertOptions = {}): Promise<SweetAlertResult> {
    return this.show('alert', options)
  }

  /**
   * 显示自动消失提示
   * @param options SweetAlert2 配置选项
   * @returns 包含用户选择的结果
   */
  public toast(options: SweetAlertOptions = {}): Promise<SweetAlertResult> {
    return this.show('toast', options)
  }

  /**
   * 显示自定义对话框
   * @param options SweetAlert2 配置选项
   * @returns 包含用户选择的结果
   */
  public custom(options: SweetAlertOptions = {}): Promise<SweetAlertResult> {
    const mergedConfig = this.mergeHandler.deepMergeSweetAlert(
      {},
      this.BASE_CONFIG,
      {
        theme: ToolKit.browser.theme.isDarkMode() ? 'dark' : 'light',
      },
      options,
    )

    return Swal.fire(mergedConfig)
  }

  /**
   * 显示 Toast
   * @param type 预设类型: 'confirm'|'reset'|'alert'|'toast'
   * @param options SweetAlert2 配置选项
   * @returns 包含用户选择的结果
   */
  private show(type: keyof typeof this.PRESETS, options: SweetAlertOptions = {}): Promise<SweetAlertResult> {
    if (!(type in this.PRESETS)) {
      console.warn(`未知的 Toast 类型: ${type}, 默认使用 toast 样式`)
      type = 'toast'
    }

    const mergedConfig = this.mergeHandler.deepMergeSweetAlert(
      {},
      this.BASE_CONFIG,
      this.PRESETS[type],
      {
        theme: ToolKit.browser.theme.isDarkMode() ? 'dark' : 'light',
      },
      options,
    )

    return Swal.fire(mergedConfig)
  }

  /**
   * 关闭当前 Toast
   */
  close(): void {
    Swal.close()
  }
}

/**
 * 获取 SweetAlert2 Style 标签
 */
export function getSwalStyleElements(): HTMLStyleElement[] {
  return Array.from(document.head.querySelectorAll('style:not([id])'))
    .filter((element): element is HTMLStyleElement => {
      const styleElement = element as HTMLStyleElement
      return (styleElement.textContent?.includes('--swal2-outline') && !styleElement.id) ?? false
    })
}
